home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / Kibitz / AEchess.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  56.8 KB  |  1,923 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        aechess.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved.
  9. **
  10. ** This is the custom AppleEvents code.  The required AppleEvents code is in
  11. ** the file AppleEvents.c, which is Keith Rollin's work. */
  12.  
  13.  
  14.  
  15. /*****************************************************************************/
  16.  
  17.  
  18.  
  19. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  20. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  21. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  22.  
  23. #ifndef __AEUTILS__
  24. #include <AEUtils.h>
  25. #endif
  26.  
  27. #ifndef __ERRORS__
  28. #include <Errors.h>
  29. #endif
  30.  
  31. #ifndef __FONTS__
  32. #include <Fonts.h>
  33. #endif
  34.  
  35. #ifndef __LOWMEM__
  36. #include <LowMem.h>
  37. #endif
  38.  
  39. #ifndef __MEMORY__
  40. #include <Memory.h>
  41. #endif
  42.  
  43. #ifndef __NOTIFICATION__
  44. #include <Notification.h>
  45. #endif
  46.  
  47. #ifndef __OSUTILS__
  48. #include <OSUtils.h>
  49. #endif
  50.  
  51. #ifndef __PPC__
  52. #include "PPC.h"
  53. #endif
  54.  
  55. #ifndef __RESOURCES__
  56. #include <Resources.h>
  57. #endif
  58.  
  59. #ifndef __SOUND__
  60. #include <Sound.h>
  61. #endif
  62.  
  63. #ifndef __STRING__
  64. #include <String.h>
  65. #endif
  66.  
  67. #ifndef __TOOLUTILS__
  68. #include <ToolUtils.h>
  69. #endif
  70.  
  71. #ifndef __TEXTEDITCONTROL__
  72. #include <TextEditControl.h>
  73. #endif
  74.  
  75. #ifndef __UTILITIES__
  76. #include <Utilities.h>
  77. #endif
  78.  
  79.  
  80.  
  81. /*****************************************************************************/
  82.  
  83.  
  84.  
  85. #define PRIORITY        kAENormalPriority
  86. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  87.  
  88.  
  89.  
  90. /*****************************************************************************/
  91.  
  92.  
  93.  
  94. static pascal void    CancelNotify(NMRecPtr nmReqPtr);
  95. static void            GetFullPathAndAppName(StringPtr path, StringPtr app);
  96.  
  97. static void            GetAppFullPath(StringPtr path);
  98.  
  99.  
  100.  
  101. /*****************************************************************************/
  102.  
  103.  
  104.  
  105. struct triplets{
  106.     AEEventClass        theEventClass;
  107.     AEEventID            theEventID;
  108.     ProcPtr                theHandler;
  109.     AEEventHandlerUPP    theUPP;
  110. };
  111. typedef struct triplets triplets;
  112. static triplets keywordsToInstall[] = {
  113.     { kCoreEventClass,        kAEAnswer,                (ProcPtr)DoAEAnswer,    nil },
  114.     { kCustomEventClass,    kibitzAESendGame,        (ProcPtr)ReceiveGame,    nil },
  115.     { kCustomEventClass,    kibitzAESendMssg,        (ProcPtr)ReceiveMssg,    nil }
  116. };        /* These are the custom AppleEvents. */
  117.  
  118.  
  119.  
  120. /*****************************************************************************/
  121.  
  122.  
  123.  
  124. extern Boolean        gHasAppleEvents;
  125. extern Boolean        gHasPPCToolbox;
  126.  
  127. extern RgnHandle    gCurrentCursorRgn;
  128. extern Cursor        *gCurrentCursor;
  129.  
  130. extern short        gMenuMods;
  131.  
  132.  
  133.  
  134. /*****************************************************************************/
  135. /*****************************************************************************/
  136.  
  137.  
  138.  
  139. /* InitCustomAppleEvents
  140. **
  141. ** Install our custom AppleEvents.  This is done in addition to installing
  142. ** the required AppleEvents.  InitAppleEvents, which installs the required
  143. ** AppleEvents, must be called first, since it sets up some global values. */
  144.  
  145. #pragma segment AppleEvents
  146. void    InitCustomAppleEvents(void)
  147. {
  148.     OSErr    err;
  149.     short    i;
  150.  
  151.     if (gHasAppleEvents) {
  152.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
  153.  
  154.             if (!keywordsToInstall[i].theUPP)
  155.                 keywordsToInstall[i].theUPP = NewAEEventHandlerProc(keywordsToInstall[i].theHandler);
  156.  
  157.             err = AEInstallEventHandler(
  158.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  159.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  160.                 keywordsToInstall[i].theUPP,        /* The AppleEvent handler. */
  161.                 0L,                                    /* Unused refcon.           */
  162.                 false                                /* Only for our app.       */
  163.             );
  164.  
  165.             if (err) {
  166.                 Alert(rErrorAlert, gAlertFilterUPP);
  167.                 return;
  168.             }
  169.         }
  170.     }
  171. }
  172.  
  173.  
  174.  
  175. /*****************************************************************************/
  176.  
  177.  
  178.  
  179. #pragma segment AppleEvents
  180. pascal OSErr    DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon)
  181. {
  182. #ifndef __MWERKS__
  183. #pragma unused (refcon)
  184. #endif
  185.  
  186.     OSErr    err;
  187.  
  188.     gCurrentCursor = nil;
  189.         /* Force re-calc of cursor region and cursor to use. */
  190.  
  191.     err = ReceiveGameReply(message, reply);
  192.  
  193.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  194.         reply,                    /* The AppleEvent.              */
  195.         keyReplyErr,            /* AEKeyword                 */
  196.         typeShortInteger,        /* Desired type.             */
  197.         (Ptr)&err,                /* Pointer to area for data. */ 
  198.         sizeof(short)            /* Size of data area.         */
  199.     );
  200.  
  201.     return(noErr);
  202. }
  203.  
  204.  
  205.  
  206. /*****************************************************************************/
  207.  
  208.  
  209.  
  210. /* SendGame
  211. **
  212. ** This routine acquires an opponent and sends the opponent the current game.
  213. ** Various changes are made to the game record to indicate that this game
  214. ** has an opponent, which color we are, where we are located (so the
  215. ** opponent can send moves back), the ID of our game, etc.  Once this
  216. ** information is in the game record, the game is transmitted to the
  217. ** opponent.  Upon receiving the game, the opponent sends back confirmation,
  218. ** which also includes the ID of the game on the opponent's end.  The return
  219. ** information is sent back as via AEAnswer, so we will extablish a two-player
  220. ** game until we receive this event.  Once we do establish a two-player game,
  221. ** we will store the opponent's game ID in the game record as well.  With our
  222. ** ID and the opponents ID, we will be able to determine which game the data
  223. ** is for at both ends.  This allows two opponents to play multiple games with
  224. ** the same machines. */
  225.  
  226. void    TogglePPCPatches(Boolean on);
  227.  
  228. #pragma segment AppleEvents
  229. OSErr    SendGame(FileRecHndl frHndl, short sendReason, StringPtr nbpType)
  230. {
  231.     AEAddressDesc    locOfOpponent;
  232.     Boolean            twoPlayer;
  233.     OSErr            err;
  234.     AEDescList        sendGameList;
  235.     long            gameID[2], size, timeout;
  236.     char            hstate;
  237.     Ptr                ptr1, ptr2;
  238.     GameListHndl    gameMoves;
  239.     AppleEvent        theAevt, reply;
  240.     short            replyType;
  241.     Str255            macText, appText, opponentName, reconnectPath;
  242.     Str32            reconnectApp;
  243.     Handle            userNameHndl;
  244.     static PPCFilterUPP    kibitzPortFilterUPP;
  245.  
  246.     sendGameList.dataHandle = theAevt.dataHandle = reply.dataHandle = nil;
  247.         /* Make sure disposing of the descriptors is okay in all cases.
  248.         ** This will not be necessary after 7.0b3, since the calls that
  249.         ** attempt to create the descriptors will nil automatically
  250.         ** upon failure. */
  251.  
  252.     err = noErr;
  253.         /* We may not make the first operation that can cause an error,
  254.         ** so we have to initialize err. */
  255.  
  256.     locOfOpponent.dataHandle = nil;
  257.         /* Make it safe to dispose of in all cases. */
  258.  
  259.     if ((*frHndl)->doc.resync < ((*frHndl)->doc.sendReason = sendReason))
  260.         (*frHndl)->doc.resync = sendReason;
  261.             /* Bump up resync, if needed. */
  262.  
  263.     UpdateTime(frHndl, false);
  264.         /* Make sure timers are current before we give them to opponent. */
  265.  
  266.     twoPlayer = (*frHndl)->doc.twoPlayer;
  267.     if (!twoPlayer) {            /* If we don't have a live opponent yet... */
  268.         GetIndString(macText, rPPCText, sTitleText);
  269.         GetIndString(appText, rPPCText, sAppText);
  270.  
  271.         if ((*frHndl)->doc.reconnectZone[0]) {
  272.             for (timeout = TickCount() + 600; timeout > TickCount();) {
  273.                 err = GetRemoteProcessTarget(frHndl, &locOfOpponent, KibitzFilter);
  274.                 if (err) break;
  275.                 if (locOfOpponent.dataHandle) break;
  276.             }
  277.         }
  278.         else {
  279. #ifndef powerc
  280.             if (gMenuMods & shiftKey) TogglePPCPatches(true);
  281. #endif
  282.             if (!kibitzPortFilterUPP)
  283.                 kibitzPortFilterUPP = NewPPCFilterProc (KibitzPortFilter);
  284.             err = MakeTarget(&locOfOpponent, false, kAEWaitReply,
  285.                 macText, appText, kibitzPortFilterUPP, (char *)nbpType);
  286.                     /* Generate the target for our opponent. */
  287. #ifndef powerc
  288.             if (gMenuMods & shiftKey) TogglePPCPatches(false);
  289. #endif
  290.         }
  291.  
  292.         (*frHndl)->doc.gameID_0      = gameID[0] = (TickCount() & 0xFFFFFFFE);
  293.         (*frHndl)->doc.gameID_1      = gameID[0];
  294.         (*frHndl)->doc.locOfOpponent = locOfOpponent;
  295.     }
  296.     else locOfOpponent = (*frHndl)->doc.locOfOpponent;
  297.  
  298.     if (!err) {        /* If we have an opponent... */
  299.         err = AECreateList(        /* CREATE THE LIST TO HOLD THE GAME. */
  300.             nil,                /* No factoring.             */
  301.             0,                    /* No factoring.             */
  302.             false,                /* Not an AppleEvent record. */
  303.             &sendGameList        /* List descriptor.             */
  304.         );
  305.     }
  306.  
  307.     if (!err) {        /* If we have an empty list to add to... */
  308.         hstate = LockHandleHigh((Handle)frHndl);
  309.         ptr1   = (Ptr)&((*frHndl)->doc);
  310.         ptr2   = (Ptr)&((*frHndl)->doc.endSendInfo);
  311.         size   = (long)ptr2 - (long)ptr1;
  312.         err = AEPutPtr(        /* ADD BOARD INFO TO THE APPLEEVENT. */
  313.             &sendGameList,    /* List to add to.                     */
  314.             1L,                /* Make this element #1.             */
  315.             typeTheBoard,    /* It is a descriptor for the board. */
  316.             ptr1,            /* Pointer to the board data.         */
  317.             size            /* Size of the board data.             */
  318.         );
  319.         HSetState((Handle)frHndl, hstate);
  320.     }
  321.  
  322.     /* For a new opponent, the field twoPlayer in sendGameList (to be sent
  323.     ** to the opponent) indicates that there is no live opponent.  When the
  324.     ** receiver gets a board with twoPlayer false, this indicates a new game
  325.     ** is being set up.  If twoPlayer is true, then it is an existing game. */
  326.  
  327.     if (!err) {        /* If we could add the board info to the list... */
  328.         gameMoves = (*frHndl)->doc.gameMoves;
  329.         size      = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  330.         hstate    = LockHandleHigh((Handle)gameMoves);
  331.         err = AEPutPtr(            /* ADD GAME MOVES TO THE LIST.             */
  332.             &sendGameList,        /* List to add to.                         */
  333.             2L,                    /* Make this element #2.                 */
  334.             typeGameMoves,        /* Descriptor for the moves of the game. */
  335.             (Ptr)(*gameMoves),    /* Pointer to the move data.             */
  336.             size                /* Size of the move data.                 */
  337.         );
  338.         HSetState((Handle)gameMoves, hstate);
  339.     }
  340.  
  341.     if ((!err) && (!twoPlayer)) {
  342.         hstate = LockHandleHigh((Handle)frHndl);
  343.         ptr1   = (Ptr)&((*frHndl)->fileState.fss);
  344.         err = AEPutPtr(            /* ADD FSSpec TO LIST TO PASS THE GAME NAME. */
  345.             &sendGameList,        /* List to add to.         */
  346.             3L,                    /* Make this element #3. */
  347.             typeFSS,            /* FSSpec descriptor.     */
  348.             ptr1,                /* Pointer to the data.     */
  349.             sizeof(FSSpec)        /* Size of the data.     */
  350.         );
  351.         HSetState((Handle)frHndl, hstate);
  352.         if (!err) {
  353.             opponentName[0] = 0;
  354.             userNameHndl = GetResource('STR ', -16096);
  355.             if (userNameHndl)
  356.                 pcpy(opponentName, (StringPtr)(*userNameHndl));
  357.             err = AEPutPtr(            /* ADD USER NAME TO LIST. */
  358.                 &sendGameList,        /* List to add to.             */
  359.                 4L,                    /* Make this element #4.     */
  360.                 typePascal,            /* Pascal string descriptor. */
  361.                 (Ptr)opponentName,    /* Pointer to the data.         */
  362.                 opponentName[0] + 1    /* Size of the data.         */
  363.             );
  364.             if (!err) {
  365.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  366.                 err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  367.                     &sendGameList,            /* List to add to.             */
  368.                     5L,                        /* Make this element #5.     */
  369.                     typePascal2,            /* Pascal string descriptor. */
  370.                     (Ptr)reconnectPath,        /* Pointer to the data.         */
  371.                     reconnectPath[0] + 1    /* Size of the data.         */
  372.                 );
  373.                 if (!err) {
  374.                     err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  375.                         &sendGameList,            /* List to add to.             */
  376.                         6L,                        /* Make this element #5.     */
  377.                         typePascal3,            /* Pascal string descriptor. */
  378.                         (Ptr)reconnectApp,        /* Pointer to the data.         */
  379.                         reconnectApp[0] + 1        /* Size of the data.         */
  380.                     );
  381.                 }
  382.             }
  383.         }
  384.     }
  385.  
  386.     if (!err) {        /* If we could add the game moves to the list... */
  387.         err = AECreateAppleEvent(            /* CREATE EMPTY APPLEEVENT.     */
  388.             kCustomEventClass,                /* Event class.                 */
  389.             kibitzAESendGame,                /* Event ID.                 */
  390.             &locOfOpponent,                    /* Address of receiving app. */
  391.             kAutoGenerateReturnID,            /* This value causes the     */
  392.                                             /* AppleEvent manager to     */
  393.                                             /* assign a return ID that     */
  394.                                             /* is unique to the session. */
  395.             kAnyTransactionID,                /* Ignore transaction ID.     */
  396.             &theAevt                        /* Location of event.         */
  397.         );
  398.     }
  399.  
  400.     if (!err) {        /* If we have an empty AppleEvent... */
  401.         err = AEPutParamDesc(    /* PUT THE LIST INTO THE APPLEEVENT.  */
  402.             &theAevt,            /* AppleEvent to add list to.          */
  403.             keyDirectObject,    /* This is our direct (only) object.  */
  404.             &sendGameList        /* The list to add to the AppleEvent. */
  405.         );
  406.     }
  407.  
  408.     replyType = (!twoPlayer) ? kAEQueueReply : kAENoReply;
  409.         /* Queue a reply only for a new game. */
  410.  
  411.     if (!err) {        /* If we have an AppleEvent ready to send... */
  412.         err = AESend(        /* SEND APPLEEVENT.                */
  413.             &theAevt,        /* Our Apple Event to send.        */
  414.             &reply,            /* We may have a reply.            */
  415.             replyType,        /* Type of reply.                */
  416.             PRIORITY,        /* App. send priority.            */
  417.             0,                /* We aren't waiting.            */
  418.             nil,            /* We aren't waiting.            */
  419.             nil                /* EventFilterProcPtr.            */
  420.         );
  421.     }
  422.     if (replyType == kAEQueueReply)
  423.         if (locOfOpponent.descriptorType == typeProcessSerialNumber)
  424.             err = ReceiveGameReply(&reply, &reply);
  425.                 /* If we want a queue reply, and if we are sending to ourselves,
  426.                 ** then we already have the reply.  Since we are sending to
  427.                 ** ourselves, we don't have to wait for an event.  Stuff happens
  428.                 ** right away.  We're (probably) happy. */
  429.  
  430.     AEDisposeDesc(&sendGameList);
  431.     AEDisposeDesc(&theAevt);
  432.     AEDisposeDesc(&reply);
  433.         /* Dispose of the descriptors, created or not.
  434.         ** If not created, no harm done by calling. */
  435.  
  436.     if (err) {
  437.         AEDisposeDesc(&locOfOpponent);
  438.             /* If we didn't connect, get rid of the target descriptor. */
  439.  
  440.         (*frHndl)->doc.gameID_0 = 0;
  441.         (*frHndl)->doc.gameID_1 = 0;
  442.             /* Mark this window so that it will never be found if we somehow
  443.             ** do get an answer from the receiver, even after failure. */
  444.     }
  445.  
  446.     return(err);
  447. }
  448.  
  449.  
  450.  
  451. /*****************************************************************************/
  452.  
  453.  
  454.  
  455. /* This code is executed only after an game is initially sent and we receive
  456. ** an AEAnswer event.  The "answer" is acknowledgment that the opponent
  457. ** received the game and that the opponent is set up for a two-player game.
  458. ** In the reply, we receive the opponent's game ID, which is used to match
  459. ** up which game receives the AppleEvents. */
  460.  
  461. #pragma segment AppleEvents
  462. pascal OSErr    ReceiveGameReply(AppleEvent *message, AppleEvent *reply)
  463. {
  464. #ifndef __MWERKS__
  465. #pragma unused (reply)
  466. #endif
  467.  
  468.     OSErr            err, replyErr;
  469.     DescType        actualType;
  470.     long            gameID[2], actualSize, mssgSize;
  471.     char            hstate;
  472.     WindowPtr        window;
  473.     FileRecHndl        frHndl;
  474.     Handle            mssgData;
  475.     Str32            opponentName, zone, machine, application;
  476.     Str255            reconnectPath;
  477.     Str32            reconnectApp;
  478.     AEAddressDesc    locOfOpponent;
  479.     short            txFont, txSize;
  480.     Style            txFace;
  481.     WindowPtr        oldPort, curPort;
  482.  
  483.     err = AEGetParamPtr(        /* CHECK FOR A RECEIVER ERROR... */
  484.         message,                /* The AppleEvent.              */
  485.         keyReplyErr,            /* AEKeyword                 */
  486.         typeShortInteger,        /* Desired type.             */
  487.         &actualType,            /* Type code.                 */
  488.         (Ptr)&replyErr,            /* Pointer to area for data. */ 
  489.         sizeof(short),            /* Size of data area.         */
  490.         &actualSize                /* Returned size of data.     */
  491.     );
  492.     if (!err) err = replyErr;
  493.  
  494.     if (!err) {
  495.         err = AEGetParamPtr(    /* GET RECEIVER GAME ID. */
  496.             message,            /* The AppleEvent.              */
  497.             keyGameID,            /* AEKeyword                 */
  498.             typeDoubleLong,        /* Desired type.             */
  499.             &actualType,        /* Type code.                 */
  500.             (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  501.             2 * sizeof(long),    /* Size of data area.         */
  502.             &actualSize            /* Returned size of data.     */
  503.         );
  504.     }
  505.  
  506.     if (!err) {        /* If we got the receiver game ID... */
  507.  
  508.         window = GetGameWindow(gameID[1], gameID[1]);
  509.             /* The ID's are still both ours, since this is where we
  510.             ** get the receiver's ID returned.  gameID[0] holds the
  511.             ** receiver's ID, and gameID[1] holds ours. */
  512.  
  513.         if (window) {
  514.             frHndl = (FileRecHndl)GetWRefCon(window);
  515.             if (!(*frHndl)->doc.twoPlayer) {
  516.                 err = AEGetParamPtr(
  517.                     message,            /* The AppleEvent.              */
  518.                     keyPascalReply,        /* AEKeyword                 */
  519.                     typePascal,            /* Desired type.             */
  520.                     &actualType,        /* Type code.                 */
  521.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  522.                     sizeof(Str32),        /* Size of data area.         */
  523.                     &actualSize            /* Returned size of data.     */
  524.                 );
  525.  
  526.                 (*frHndl)->doc.opponentName[0] = 0;
  527.                 if (!err) {
  528.                     (*frHndl)->doc.gameID_1 = gameID[0];
  529.                     pcpy(&(*frHndl)->doc.opponentName[0], opponentName);
  530.                     SetOpponentType(frHndl, kTwoPlayer);
  531.                     locOfOpponent = (*frHndl)->doc.locOfOpponent;
  532.                     zone[0] = machine[0] = 0;
  533.                     GetTargetInfo(locOfOpponent, zone, machine, application);
  534.                     pcpy(&(*frHndl)->doc.opponentZone[0], zone);
  535.                     pcpy(&(*frHndl)->doc.opponentMachine[0], machine);
  536.  
  537.                     err = AEGetParamPtr(
  538.                         message,            /* The AppleEvent.              */
  539.                         keyPascal2Reply,    /* AEKeyword                 */
  540.                         typePascal2,        /* Desired type.             */
  541.                         &actualType,        /* Type code.                 */
  542.                         (Ptr)reconnectPath,    /* Pointer to area for data. */ 
  543.                         sizeof(Str255),        /* Size of data area.         */
  544.                         &actualSize            /* Returned size of data.     */
  545.                     );
  546.                     (*frHndl)->doc.reconnectPath[0] = 0;
  547.                     if (!err) pcpy(&(*frHndl)->doc.reconnectPath[0], reconnectPath);
  548.  
  549.                     err = AEGetParamPtr(
  550.                         message,            /* The AppleEvent.              */
  551.                         keyPascal3Reply,    /* AEKeyword                 */
  552.                         typePascal3,        /* Desired type.             */
  553.                         &actualType,        /* Type code.                 */
  554.                         (Ptr)reconnectApp,    /* Pointer to area for data. */ 
  555.                         sizeof(Str32),        /* Size of data area.         */
  556.                         &actualSize            /* Returned size of data.     */
  557.                     );
  558.                     (*frHndl)->doc.reconnectApp[0] = 0;
  559.                     if (!err) pcpy(&(*frHndl)->doc.reconnectApp[0], reconnectApp);
  560.  
  561.                     if (!err) {
  562.                         err = AEGetParamPtr(
  563.                             message,                /* The AppleEvent.              */
  564.                             keyTextMessage,            /* AEKeyword                 */
  565.                             typeMssg,                /* Desired type.             */
  566.                             &actualType,            /* Type code.                 */
  567.                             nil,                    /* Pointer to area for data. */ 
  568.                             0,                        /* Size of data area.         */
  569.                             &mssgSize                /* Returned size of data.     */
  570.                         );
  571.                     }
  572.                     mssgData = nil;
  573.                     if (!err) {        /* Get the data... */
  574.                         mssgData = NewHandle(mssgSize);
  575.                         if (mssgData) {
  576.                             hstate = LockHandleHigh(mssgData);
  577.                             err = AEGetParamPtr(
  578.                                 message,                /* The AppleEvent.              */
  579.                                 keyTextMessage,            /* AEKeyword                 */
  580.                                 typeMssg,                /* Desired type.             */
  581.                                 &actualType,            /* Type code.                 */
  582.                                 *mssgData,                /* Pointer to area for data. */ 
  583.                                 mssgSize,                /* Size of data area.         */
  584.                                 &actualSize                /* Returned size of data.     */
  585.                             );
  586.                         }
  587.                         else err = memFullErr;
  588.                     }
  589.                     if (!err) {
  590.                         oldPort = SetFilePort(frHndl);
  591.                         GetPort(&curPort);
  592.                         txFont = curPort->txFont;
  593.                         txSize = curPort->txSize;
  594.                         txFace = curPort->txFace;
  595.                         TextFont(applFont);
  596.                         TextSize(9);
  597.                         TextFace(normal);
  598.                         mssgData = CTESwapText((*frHndl)->doc.message[kMessageIn],
  599.                                                 mssgData, nil, true);
  600.                         TextFont(txFont);
  601.                         TextSize(txSize);
  602.                         TextFace(txFace);
  603.                         SetPort(oldPort);
  604.                     }
  605.                     if (mssgData) DisposeHandle(mssgData);
  606.  
  607.                     if (err == errAEDescNotFound) err = noErr;
  608.                 }
  609.                 if (err) (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  610.                 else GetDateTime(&((*frHndl)->doc.timeLastReceive));
  611.             }
  612.         }
  613.     }
  614.  
  615.     return(err);
  616. }
  617.  
  618.  
  619.  
  620. /*****************************************************************************/
  621.  
  622.  
  623.  
  624. /* ReceiveGame
  625. **
  626. ** This routine receives a board from an opponent.  It receives it for various
  627. ** purposes.  These are:
  628. **   1) Establishing a new game.
  629. **   2) Receiving a move.
  630. **   3) Receiving a new board position, due to scrolling.
  631. **
  632. ** Establishing a new game is determined by the fact that the value twoPlayer
  633. ** is false.  If it is a previously established game, then this field is true.
  634. **
  635. ** If it is a previously established game, then whether or not it is a new move
  636. ** is determined by field "sendReason".  If sendReason != kIsMove, then it is some
  637. ** other change, such as scrolling or resyncing by of the sender.
  638. ** These other cases should not cause a win/loss/tie dialog to appear.
  639. **
  640. ** If it is a regular move, (sendReason == kIsMove), then the win/loss/draw dialogs
  641. ** should be displayed, if the game is indeed over after the move. */
  642.  
  643. #pragma segment AppleEvents
  644. pascal OSErr    ReceiveGame(AppleEvent *message, AppleEvent *reply, long refcon)
  645. {
  646. #ifndef __MWERKS__
  647. #pragma unused (refcon)
  648. #endif
  649.  
  650.     OSErr            err;
  651.     FileRecHndl        frHndl, newFrHndl, oldFrHndl, mssgFrHndl;
  652.     FileRecPtr        frPtr;
  653.     AEDescList        receiveGameList;
  654.     char            hstate;
  655.     Ptr                ptr1, ptr2;
  656.     long            size, gameID[2];
  657.     Boolean            twoPlayer;
  658.     AEAddressDesc    senderTarget;
  659.     AEKeyword        ignoredKeyWord;
  660.     DescType        ignoredType;
  661.     Size            ignoredSize;
  662.     GameListHndl    gameMoves;
  663.     WindowPtr        oldPort, window, fwindow, behindWindow;
  664.     WindowPeek        wpeek;
  665.     FSSpec            myFSS;
  666.     Str32            opponentName, zone, machine, application;
  667.     Str255            reconnectPath;
  668.     Str32            reconnectApp;
  669.     Handle            userNameHndl, hText;
  670.     short            i, drawBtnState, sendReason, myColor, invertBoard, fromSq, toSq;
  671.     GameListHndl    oldGame, newGame;
  672.     GameElement        *optr, *nptr;
  673.     short            oldGameIndex, newGameIndex, oldNumMoves, newNumMoves, identical;
  674.     TEHandle        te;
  675.  
  676.     err = noErr;
  677.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  678.         reply,                    /* The AppleEvent.              */
  679.         keyReplyErr,            /* AEKeyword                 */
  680.         typeShortInteger,        /* Desired type.             */
  681.         (Ptr)&err,                /* Pointer to area for data. */ 
  682.         sizeof(short)            /* Size of data area.         */
  683.     );
  684.  
  685.     receiveGameList.dataHandle = nil;
  686.         /* Make sure disposing of the descriptors is okay in all cases.
  687.         ** This will not be necessary after 7.0b3, since the calls that
  688.         ** attempt to create the descriptors will nil automatically
  689.         ** upon failure. */
  690.  
  691.     IncNewFileNum(false);
  692.     err = AppNewDocument(&newFrHndl, ksOrigName);
  693.     IncNewFileNum(true);
  694.  
  695.     if (err) return(err);
  696.  
  697.     /* We have a new document... */
  698.     err = AEGetParamDesc(    /* GET THE APPLEEVENT LIST.  */
  699.         message,            /* AppleEvent to holding list.          */
  700.         keyDirectObject,    /* This is our direct (only) object.  */
  701.         typeWildCard,        /* Desired type is game list.          */
  702.         &receiveGameList    /* The list to add to the AppleEvent. */
  703.     );
  704.  
  705.     if (!err) {        /* If we got the list descriptor... */
  706.         hstate = LockHandleHigh((Handle)newFrHndl);
  707.         ptr1   = (Ptr)&((*newFrHndl)->doc);
  708.         ptr2   = (Ptr)&((*newFrHndl)->doc.endSendInfo);
  709.         size   = (long)ptr2 - (long)ptr1;
  710.         err = AEGetNthPtr(        /* GET BOARD INFO FROM THE LIST.     */
  711.             &receiveGameList,    /* List to get from.                 */
  712.             1L,                    /* Get first item in list.             */
  713.             typeTheBoard,        /* First item is the board.             */
  714.             &ignoredKeyWord,    /* Returned keyword -- we know.         */
  715.             &ignoredType,        /* Returned type -- we know.         */
  716.             ptr1,                /* Where to put the board info.         */
  717.             size,                /* Size of the board.                 */
  718.             &ignoredSize        /* Actual size -- we know.             */
  719.         );
  720.         HSetState((Handle)newFrHndl, hstate);
  721.     }
  722.  
  723.     if (!err) {        /* If we got the board... */
  724.         gameMoves = (*newFrHndl)->doc.gameMoves;
  725.         size      = (*newFrHndl)->doc.numGameMoves * sizeof(GameElement);
  726.         SetHandleSize((Handle)gameMoves, size);
  727.         err = MemError();
  728.         if (!err) {
  729.             hstate = LockHandleHigh((Handle)gameMoves);
  730.             err = AEGetNthPtr(        /* GET GAME MOVES FROM THE LIST.     */
  731.                 &receiveGameList,    /* List to get from.                 */
  732.                 2L,                    /* Get second item in list.             */
  733.                 typeGameMoves,        /* Second item is the game moves.     */
  734.                 &ignoredKeyWord,    /* Returned keyword -- we know.         */
  735.                 &ignoredType,        /* Returned type -- we know.         */
  736.                 (Ptr)(*gameMoves),    /* Where to put the moves.             */
  737.                 size,                /* Size of the board.                 */
  738.                 &ignoredSize        /* Actual size -- we know.             */
  739.             );
  740.             HSetState((Handle)gameMoves, hstate);
  741.         }
  742.     }
  743.  
  744.  
  745.  
  746.     if (!err) {
  747.  
  748.         /* We now have the board and game moves, in newFrHndl.  This is either a
  749.         ** new opponent, or an update from an old opponent.  Let's see... */
  750.  
  751.         twoPlayer = (*newFrHndl)->doc.twoPlayer;
  752.         (*newFrHndl)->doc.twoPlayer = false;
  753.             /* See if this is an already existing opponent, or a new one. */
  754.     
  755.         if (!twoPlayer) {        /* If new game... */
  756.             err = AEGetAttributeDesc(    /* GET ADDRESS OF NEW OPPONENT.     */
  757.                 message,                /* Get address of sender from message.         */
  758.                 keyAddressAttr,            /* We want an address.                         */
  759.                 typeWildCard,            /* We want the address of the sender.         */
  760.                 &senderTarget            /* Address of sender.                         */
  761.             );
  762.             if (!err) {
  763.                 (*newFrHndl)->doc.twoPlayer     = true;
  764.                 (*newFrHndl)->doc.arrangeBoard  = false;
  765.                 (*newFrHndl)->doc.locOfOpponent = senderTarget;
  766.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  767.                     &receiveGameList,    /* List to get from.            */
  768.                     3L,                    /* Get second item in list.        */
  769.                     typeFSS,            /* Third item is the FSSpec.    */
  770.                     &ignoredKeyWord,    /* Returned keyword -- we know. */
  771.                     &ignoredType,        /* Returned type -- we know.    */
  772.                     (Ptr)&myFSS,        /* Where to put the FSSpec.        */
  773.                     sizeof(FSSpec),        /* Size of the data.            */
  774.                     &ignoredSize        /* Actual size -- we know.        */
  775.                 );
  776.                 if (!err)
  777.                     pcpy((*newFrHndl)->fileState.fss.name, myFSS.name);
  778.             }
  779.             if (!err) {
  780.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  781.                     &receiveGameList,    /* List to get from.                */
  782.                     4L,                    /* Get second item in list.            */
  783.                     typePascal,            /* Third item is the opponent name.    */
  784.                     &ignoredKeyWord,    /* Returned keyword -- we know.     */
  785.                     &ignoredType,        /* Returned type -- we know.        */
  786.                     (Ptr)opponentName,    /* Where to put the opponent name.    */
  787.                     sizeof(Str32),        /* Size of the data.                */
  788.                     &ignoredSize        /* Actual size.                        */
  789.                 );
  790.                 (*newFrHndl)->doc.opponentName[0] = 0;
  791.                 if (!err) {
  792.                     pcpy((*newFrHndl)->doc.opponentName, opponentName);
  793.                     zone[0] = machine[0] = 0;
  794.                     GetTargetInfo(senderTarget, zone, machine, application);
  795.                     pcpy((*newFrHndl)->doc.opponentZone, zone);
  796.                     pcpy((*newFrHndl)->doc.opponentMachine, machine);
  797.                     GetDateTime(&((*newFrHndl)->doc.timeLastReceive));
  798.                 }
  799.                 if (!err) {
  800.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  801.                         &receiveGameList,    /* List to get from.                */
  802.                         5L,                    /* Get second item in list.            */
  803.                         typePascal2,        /* Third item is the opponent name.    */
  804.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  805.                         &ignoredType,        /* Returned type -- we know.        */
  806.                         (Ptr)reconnectPath,    /* Where to put the opponent name.    */
  807.                         sizeof(Str255),        /* Size of the data.                */
  808.                         &ignoredSize        /* Actual size.                        */
  809.                     );
  810.                     (*newFrHndl)->doc.reconnectPath[0] = 0;
  811.                     if (!err) pcpy((*newFrHndl)->doc.reconnectPath, reconnectPath);
  812.                 }
  813.                 if (!err) {
  814.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  815.                         &receiveGameList,    /* List to get from.                */
  816.                         6L,                    /* Get second item in list.            */
  817.                         typePascal3,        /* Third item is the opponent name.    */
  818.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  819.                         &ignoredType,        /* Returned type -- we know.        */
  820.                         (Ptr)reconnectApp,    /* Where to put the opponent name.    */
  821.                         sizeof(Str32),        /* Size of the data.                */
  822.                         &ignoredSize        /* Actual size.                        */
  823.                     );
  824.                     (*newFrHndl)->doc.reconnectApp[0] = 0;
  825.                     if (!err) pcpy((*newFrHndl)->doc.reconnectApp, reconnectApp);
  826.                 }
  827.             }
  828.         }
  829.     }
  830.  
  831.     if (!err) {        /* If we got the opponent address... */
  832.  
  833.         if (!twoPlayer) {        /* It is a new game... */
  834.  
  835.             (*newFrHndl)->doc.timerRefTick = TickCount();
  836.                 /* Set the timer reference early as possible.
  837.                 ** This syncs the two clocks as much as possible. */
  838.  
  839.                 /* For a new opponent, then we need to ID the receiver side
  840.                 ** of the sender/receiver ID pair.  We also need to send
  841.                 ** back the receiver portion of the ID pair for the sender. */
  842.  
  843.             (*newFrHndl)->doc.gameID_0 = gameID[0] = (TickCount() | 0x01);
  844.             (*newFrHndl)->doc.myColor     ^= 1;
  845.             (*newFrHndl)->doc.invertBoard ^= 1;
  846.                 /* We are the opposite color/side as the opponent. */
  847.  
  848.             if ((*newFrHndl)->doc.version != kVersion) err = errAEWrongDataType;
  849.                 /* Incompatible file format. */
  850.  
  851.             if (!err) {
  852.                 gameID[1] = (*newFrHndl)->doc.gameID_1;
  853.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  854.                     reply,                /* The AppleEvent.              */
  855.                     keyGameID,            /* AEKeyword                 */
  856.                     typeDoubleLong,        /* Type code.                 */
  857.                     (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  858.                     2 * sizeof(long)    /* Size of data area.         */
  859.                 );
  860.             }
  861.  
  862.             if (!err) {
  863.                 opponentName[0] = 0;
  864.                 userNameHndl = GetResource('STR ', -16096);
  865.                 if (userNameHndl)
  866.                     pcpy(opponentName, (StringPtr)(*userNameHndl));
  867.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  868.                     reply,                /* The AppleEvent.              */
  869.                     keyPascalReply,        /* AEKeyword                 */
  870.                     typePascal,            /* Type code.                 */
  871.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  872.                     opponentName[0] + 1    /* Size of data area.         */
  873.                 );
  874.             }
  875.  
  876.             if (!err) {
  877.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  878.                 err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  879.                     reply,                    /* The AppleEvent.              */
  880.                     keyPascal2Reply,        /* AEKeyword                 */
  881.                     typePascal2,            /* Type code.                 */
  882.                     (Ptr)reconnectPath,        /* Pointer to area for data. */ 
  883.                     reconnectPath[0] + 1    /* Size of data area.         */
  884.                 );
  885.                 if (!err) {
  886.                     err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  887.                         reply,                    /* The AppleEvent.              */
  888.                         keyPascal3Reply,        /* AEKeyword                 */
  889.                         typePascal3,            /* Type code.                 */
  890.                         (Ptr)reconnectApp,        /* Pointer to area for data. */ 
  891.                         reconnectApp[0] + 1    /* Size of data area.         */
  892.                     );
  893.                 }
  894.             }
  895.  
  896.             if (!err) {
  897.                 if (IsAppWindow(fwindow = FrontWindow())) {
  898.                     frPtr = *(frHndl = (FileRecHndl)GetWRefCon(fwindow));
  899.                     if (
  900.                         (frPtr->doc.myColor != kMessageDoc) &&
  901.                         (!(frPtr->doc.arrangeBoard)) &&
  902.                         (!(frPtr->doc.twoPlayer)) &&
  903.                         (!(frPtr->doc.numGameMoves)) &&
  904.                         (!(frPtr->doc.gameID_0)) &&
  905.                         (!(frPtr->doc.timeLastReceive))
  906.                     ) {
  907.                         AppDisposeDocument(frHndl);
  908.                         DisposeAnyWindow(fwindow);
  909.                     }
  910.                 }
  911.                 behindWindow = (WindowPtr)-1;
  912.                 for (wpeek = LMGetWindowList(); wpeek; wpeek = wpeek->nextWindow) {
  913.                     if (IsAppWindow((WindowPtr)wpeek)) {
  914.                         frPtr = *(FileRecHndl)GetWRefCon((WindowPtr)wpeek);
  915.                         if (
  916.                             (frPtr->doc.myColor != kMessageDoc) &&
  917.                             (!(frPtr->doc.arrangeBoard)) &&
  918.                             (!(frPtr->doc.twoPlayer)) &&
  919.                             (!(frPtr->doc.numGameMoves))
  920.                         ) break;
  921.                         behindWindow = (WindowPtr)wpeek;
  922.                     }
  923.                 }
  924.                 err = AppNewWindow(newFrHndl, nil, behindWindow);
  925.             }
  926.  
  927.                 /* If everything worked for new opponent, give the new document a window. */
  928.  
  929.             if (!err) {
  930.                 AdjustGameSlider(newFrHndl);
  931.  
  932.                 DrawButtonTitle(newFrHndl, kTwoPlayer);
  933.                     /* Convert the draw button to two player. */
  934.  
  935.                 (*newFrHndl)->doc.gotUpdateTick = TickCount();
  936.                     /* Record when we got the event. */
  937.  
  938.                 fwindow = FrontWindow();
  939.                 mssgFrHndl = (FileRecHndl)GetWRefCon((WindowPtr)fwindow);
  940.                 if ((*mssgFrHndl)->doc.myColor == kMessageDoc) {
  941.                     te     = (*mssgFrHndl)->doc.message[kMessageOut];
  942.                     hText  = (*te)->hText;
  943.                     hstate = LockHandleHigh(hText);
  944.                     size   = (*te)->teLength;
  945.                     err = AEPutParamPtr(
  946.                         reply,
  947.                         keyTextMessage,
  948.                         typeMssg,
  949.                         *hText,
  950.                         size
  951.                     );
  952.                     HSetState(hText, hstate);
  953.                 }
  954.             }
  955.         }
  956.         else {        /* It is an update to an existing game. */
  957.  
  958.             window = GetGameWindow(
  959.                 (*newFrHndl)->doc.gameID_1, (*newFrHndl)->doc.gameID_0);
  960.                     /* Get the window for the existing game. */
  961.  
  962.             if (window) {        /* This game still exists... */
  963.  
  964.                 oldFrHndl = (FileRecHndl)GetWRefCon(window);
  965.                 UpdateTime(oldFrHndl, false);
  966.  
  967.                 if ((*oldFrHndl)->doc.resync < (sendReason = (*newFrHndl)->doc.sendReason))
  968.                     (*oldFrHndl)->doc.resync = sendReason;
  969.                         /* Bump up resync, if needed. */
  970.  
  971.                 if (sendReason == kScrolling) {
  972.                     if (
  973.                         ((*oldFrHndl)->doc.resync == kResync) || 
  974.                         ((*oldFrHndl)->doc.gotUpdateTick + 30 > TickCount())
  975.                     ) {
  976.                         window = nil;
  977.                         AppDisposeDocument(newFrHndl);
  978.                                 /* Temporary document now gone. */
  979.                     }    /* If it has been less than 1/2 second since the last
  980.                         ** scroll update received, or if the user has finished
  981.                         ** scrolling, then we can ignore this scroll event.
  982.                         ** This keeps us from getting behind in the processing
  983.                         ** of scroll events. */
  984.                 }
  985.             }
  986.             else
  987.                 err = memFullErr;
  988.                     /* Can't find the old window, so cause some kind of error. */
  989.  
  990.             if (window) {        /* This game still exists... */
  991.  
  992.                 if (sendReason != kIsMove) {
  993.                     for (i = 0; i < 2; ++i)
  994.                         (*newFrHndl)->doc.timeLeft[i] = (*oldFrHndl)->doc.timeLeft[i];
  995.                             /* Keep our clock values if opponent is scrolling or resyncing. */
  996.                 }
  997.  
  998.                 frPtr        = *oldFrHndl;
  999.                 oldGameIndex = frPtr->doc.gameIndex;
  1000.                 oldNumMoves  = frPtr->doc.numGameMoves;
  1001.                 oldGame      = frPtr->doc.gameMoves;
  1002.                 frPtr        = *newFrHndl;
  1003.                 newGameIndex = frPtr->doc.gameIndex;
  1004.                 newNumMoves  = frPtr->doc.numGameMoves;
  1005.                 newGame      = frPtr->doc.gameMoves;
  1006.                 if ((oldGameIndex == newGameIndex) && (oldNumMoves == newNumMoves)) {
  1007.                     optr = &(**oldGame)[0];
  1008.                     nptr = &(**newGame)[0];
  1009.                     identical = true;
  1010.                     for (i = 0; i < oldNumMoves; ++i, ++optr, ++nptr) {
  1011.                         if (
  1012.                             (optr->moveFrom          != nptr->moveFrom) ||
  1013.                             (optr->moveTo            != nptr->moveTo) ||
  1014.                             (optr->pieceCaptured     != nptr->pieceCaptured) ||
  1015.                             (optr->pieceCapturedFrom != nptr->pieceCapturedFrom) ||
  1016.                             (optr->promoteTo         != nptr->promoteTo)
  1017.                         ) {
  1018.                             identical = false;
  1019.                             break;
  1020.                         }
  1021.                     }
  1022.                 }
  1023.                 else identical = false;
  1024.  
  1025.                 myColor     = (*oldFrHndl)->doc.myColor;
  1026.                 invertBoard = (*oldFrHndl)->doc.invertBoard;
  1027.                     /* These need to be saved, so they are in that section,
  1028.                     ** but they are private info, so cache them. */
  1029.  
  1030.                 ptr1 = (Ptr)&((*newFrHndl)->doc);
  1031.                 ptr2 = (Ptr)&((*newFrHndl)->doc.endFileInfo1);
  1032.                 size = (long)ptr2 - (long)ptr1;
  1033.                 ptr2 = (Ptr)&((*oldFrHndl)->doc);
  1034.                 BlockMove(ptr1, ptr2, size);
  1035.  
  1036.                 (*oldFrHndl)->doc.myColor     = myColor;
  1037.                 (*oldFrHndl)->doc.invertBoard = invertBoard;
  1038.                     /* Restore our private cached values. */
  1039.  
  1040.                 (*newFrHndl)->doc.gameMoves = (*oldFrHndl)->doc.gameMoves;
  1041.                 (*oldFrHndl)->doc.gameMoves = gameMoves;
  1042.                     /* Swap the game move handles.  The existing document
  1043.                     ** is now updated completely.  We can dispose of the
  1044.                     ** temporary new one.  (gameMoves is set above for
  1045.                     ** the handle for the new document.) */
  1046.  
  1047.                 i = (*newFrHndl)->doc.drawBtnState;
  1048.                 drawBtnState = kTwoPlayer;
  1049.                 if (i & 0x02) drawBtnState |= 0x04;
  1050.                 if (i & 0x04) drawBtnState |= 0x02;
  1051.  
  1052.                 AppDisposeDocument(newFrHndl);
  1053.                     /* Temporary document now gone. */
  1054.  
  1055.                 GetPort(&oldPort);
  1056.                 SetPort(window);
  1057.  
  1058.                 if (!identical) {        /* There was a change, so show it. */
  1059.                     if (sendReason == kIsMove) {
  1060.                     if (GetControlValue((*oldFrHndl)->doc.beepOnMove)) SysBeep(1);
  1061.                         if (GameStatus(oldFrHndl) <= kDrawByRep) {
  1062.                             MakeMove(oldFrHndl, -1, 0, 0);
  1063.                             oldGame      = (*oldFrHndl)->doc.gameMoves;
  1064.                             oldGameIndex = (*oldFrHndl)->doc.gameIndex;
  1065.                             fromSq = (**oldGame)[oldGameIndex].moveFrom;
  1066.                             toSq   = (**oldGame)[oldGameIndex].moveTo;
  1067.                             SlideThePiece(oldFrHndl, fromSq, toSq);
  1068.                             MakeMove(oldFrHndl, 1, 0, 0);
  1069.                             SayTheMove(oldFrHndl);
  1070.                         }
  1071.                     }
  1072.                     ImageDocument(oldFrHndl, true);
  1073.                     AdjustGameSlider(oldFrHndl);
  1074.                 }
  1075.  
  1076.                 DrawButtonTitle(oldFrHndl, drawBtnState);
  1077.                 UpdateGameStatus(oldFrHndl);
  1078.                     /* Update the text of the draw button. */
  1079.  
  1080.                 DrawTime(oldFrHndl);
  1081.  
  1082.                 (*oldFrHndl)->doc.gotUpdateTick = TickCount();
  1083.                     /* Record when we got the event. */
  1084.  
  1085.                 if (sendReason == kIsMove) {
  1086.                     (*oldFrHndl)->fileState.docDirty = true;
  1087.                     AlertIfGameOver(oldFrHndl);
  1088.                         /* For non-moves, we don't want to beep or
  1089.                         ** show a game-over dialog. */
  1090.                 }
  1091.                 SetPort(oldPort);
  1092.             }
  1093.         }
  1094.     }
  1095.  
  1096.     if (err) AppDisposeDocument(newFrHndl);
  1097.         /* This won't get done twice, even though there is an
  1098.         ** AppDisposeDocument(newFrHndl) earlier.  The earlier
  1099.         ** one only happens if no error occured, and this one
  1100.         ** only happens on an error condition. */
  1101.  
  1102.     AEDisposeDesc(&receiveGameList);
  1103.         /* Dispose of the descriptors, created or not.
  1104.         ** If not created, no harm done by calling. */
  1105.  
  1106.     if (!err) NotifyUser();
  1107.     return(err);
  1108. }
  1109.  
  1110.  
  1111.  
  1112. /*****************************************************************************/
  1113.  
  1114.  
  1115.  
  1116. /* Send one of various messages to the opponent.  There is a common set of
  1117. ** data that needs to be sent so that the opponent can determine which game
  1118. ** the message should be applied.  Then there is message-specific data that
  1119. ** is handled case by case.  Once the message is completed, it is sent off
  1120. ** to the opponent.  The additional task of updating the state of our game
  1121. ** is also handled here.  For example:  When text is sent, the text on our
  1122. ** machine is selected to make it easier to replace the old text with new
  1123. ** text.  Any typing by the user will replace the selected text (all the text)
  1124. ** with the newly typed text.  */
  1125.  
  1126. #pragma segment AppleEvents
  1127. Boolean    SendMssg(FileRecHndl frHndl, short messageType)
  1128. {
  1129.     AEAddressDesc    locOfOpponent;
  1130.     OSErr            err;
  1131.     TEHandle        teIn, teOut;
  1132.     char            hstate;
  1133.     AppleEvent        theAevt, reply;
  1134.     Handle            hText, snd, intxt, outtxt;
  1135.     RgnHandle        oldClip, newClip;
  1136.     TextStyle        styl;
  1137.     long            size, gameID[2], time[2];
  1138.     short            i, inlen, outlen, overflow;
  1139.     Boolean            twoPlayer;
  1140.     WindowPtr        oldPort, curPort;
  1141.     Point            pt;
  1142.     short            txFont, txSize;
  1143.     Style            txFace;
  1144.  
  1145.     oldPort = SetFilePort(frHndl);
  1146.     GetPort(&curPort);
  1147.  
  1148.     theAevt.dataHandle = reply.dataHandle = nil;
  1149.         /* Make sure disposing of the descriptors is okay in all cases.
  1150.         ** This will not be necessary after 7.0b3, since the calls that
  1151.         ** attempt to create the descriptors will nil automatically
  1152.         ** upon failure. */
  1153.  
  1154.     err = noErr;
  1155.  
  1156.     twoPlayer = (*frHndl)->doc.twoPlayer;
  1157.     if (twoPlayer) {
  1158.  
  1159.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1160.  
  1161.         err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  1162.             kCustomEventClass,            /* Event class.                 */
  1163.             kibitzAESendMssg,            /* Event ID.                 */
  1164.             &locOfOpponent,                /* Address of receiving app. */
  1165.             kAutoGenerateReturnID,        /* This value causes the     */
  1166.                                         /* AppleEvent manager to     */
  1167.                                         /* assign a return ID that     */
  1168.                                         /* is unique to the session. */
  1169.             kAnyTransactionID,            /* Ignore transaction ID.     */
  1170.             &theAevt                    /* Location of event.         */
  1171.         );
  1172.  
  1173.         if (!err) {            /* Say what the message is. */
  1174.             AEPutParamPtr(
  1175.                 &theAevt,
  1176.                 keyDirectObject,
  1177.                 typeShortInteger,
  1178.                 (Ptr)&messageType,
  1179.                 sizeof(short)
  1180.             );
  1181.         }
  1182.  
  1183.         if (!err) {            /* Say what window message is for. */
  1184.             gameID[0] = (*frHndl)->doc.gameID_0;
  1185.             gameID[1] = (*frHndl)->doc.gameID_1;
  1186.             AEPutParamPtr(
  1187.                 &theAevt,
  1188.                 keyGameID,
  1189.                 typeDoubleLong,
  1190.                 (Ptr)&gameID[0],
  1191.                 2 * sizeof(long)
  1192.             );
  1193.         }
  1194.     }
  1195.  
  1196.     /* The stuff that applies to all messages is now done.  Now specifically
  1197.     ** handle all the different message types. */
  1198.  
  1199.     if (!err) {
  1200.         switch (messageType) {
  1201.  
  1202.             case kAmWhiteMssg:
  1203.             case kAmBlackMssg:
  1204.                 (*frHndl)->doc.configColor       = messageType;
  1205.                 (*frHndl)->doc.configColorChange = true;
  1206.                 (*frHndl)->doc.resync            = kHandResync;
  1207.                     /* The AppleEvent already has all the data the opponent
  1208.                     ** needs.  Post that a color change is happening.  The
  1209.                     ** reason that it is posted, instead of immediately applied,
  1210.                     ** is that we want to make sure that the opponent isn't
  1211.                     ** doing a color change operation at the same time.  The
  1212.                     ** color change will only occur when we get a NULL event.
  1213.                     ** The NULL event indicates that the opponent isn't sending
  1214.                     ** any AppleEvents at that time.  Waiting for quiescence
  1215.                     ** helps prevent the state of the game from getting
  1216.                     ** confused.  Also, the creator of the game echos the
  1217.                     ** color change, just to make sure that both machines are
  1218.                     ** in the same state.  (The echo doesn't occur until
  1219.                     ** there are no other AppleEvents happening.  This helps
  1220.                     ** keep the number of AppleEvents down, as well.) */
  1221.                 break;
  1222.  
  1223.             case kDisconnectMssg:
  1224.                     /* All the information we need is already in the AppleEvent. */
  1225.                 break;
  1226.  
  1227.             case kTimeMssg:
  1228.                 for (i = 0; i < 2; ++i)
  1229.                     time[i] = (*frHndl)->doc.configTime[i] = (*frHndl)->doc.timeLeft[i];
  1230.                 if (twoPlayer) {
  1231.                     err = AEPutParamPtr(
  1232.                         &theAevt,
  1233.                         keyTime,
  1234.                         typeDoubleLong,
  1235.                         (Ptr)&time[0],
  1236.                         2 * sizeof(long)
  1237.                     );
  1238.                     if ((*frHndl)->doc.resync)
  1239.                         (*frHndl)->doc.configTimeChange = true;
  1240.                     else {
  1241.                         for (i = 0; i < 2; ++i)
  1242.                             (*frHndl)->doc.timeLeft[i] =
  1243.                                 (*frHndl)->doc.displayTime[i] =
  1244.                                     (*frHndl)->doc.configTime[i];
  1245.                         UpdateTime(frHndl, false);
  1246.                         DrawTime(frHndl);
  1247.                     }
  1248.                 }
  1249.                 break;
  1250.  
  1251.             case kTextMssg:
  1252.                 if (twoPlayer) {
  1253.                     teOut  = (*frHndl)->doc.message[kMessageOut];
  1254.                     hText  = (*teOut)->hText;
  1255.                     hstate = LockHandleHigh(hText);
  1256.                     size   = (*teOut)->teLength;
  1257.                     err = AEPutParamPtr(
  1258.                         &theAevt,
  1259.                         keyTextMessage,
  1260.                         typeMssg,
  1261.                         *hText,
  1262.                         size
  1263.                     );
  1264.                     HSetState(hText, hstate);
  1265.                 }
  1266.                 break;
  1267.  
  1268.             case kSoundMssg:
  1269.                 if (twoPlayer) {
  1270.                     snd = (*frHndl)->doc.sound;
  1271.                     if (snd) {
  1272.                         hstate = LockHandleHigh(snd);
  1273.                         size   = GetHandleSize(snd);
  1274.                         err = AEPutParamPtr(
  1275.                             &theAevt,
  1276.                             keySoundMessage,
  1277.                             typeMssg,
  1278.                             *snd,
  1279.                             size
  1280.                         );
  1281.                         HSetState(snd, hstate);
  1282.                     }
  1283.                 }
  1284.                 break;
  1285.         }
  1286.     }
  1287.  
  1288.     if (twoPlayer) {
  1289.         if (!err) {        /* If everything looks good... */
  1290.             err = AESend(                /* SEND APPLEEVENT.                 */
  1291.                 &theAevt,                /* Our Apple Event to send.         */
  1292.                 &reply,                    /* We may have a reply.             */
  1293.                 kAENoReply,                /* Don't wait for reply.         */
  1294.                 PRIORITY,                /* App. send priority.             */
  1295.                 0,                        /* We aren't waiting.             */
  1296.                 nil,                    /* We don't wait, so no idleProc */
  1297.                 nil                        /* EventFilterProcPtr.             */
  1298.             );
  1299.         }
  1300.         if (!err) {
  1301.             switch (messageType) {
  1302.                 case kTextMssg:
  1303.                     styl.tsFont = applFont;
  1304.  
  1305.                     teIn   = (*frHndl)->doc.message[kMessageIn];
  1306.                     intxt  = (*teIn)->hText;
  1307.  
  1308.                     txFont = curPort->txFont;
  1309.                     txSize = curPort->txSize;
  1310.                     txFace = curPort->txFace;
  1311.                     TextFont(styl.tsFont);
  1312.                     TextSize(9);
  1313.                     TextFace(normal);
  1314.                     outtxt = CTESwapText(teOut, NewHandle(0), nil, true);
  1315.                     TextFont(txFont);
  1316.                     TextSize(txSize);
  1317.                     TextFace(txFace);
  1318.  
  1319.                     inlen  = (*teIn)->teLength;
  1320.                     outlen = GetHandleSize(outtxt);
  1321.  
  1322.                     GetClip(oldClip = NewRgn());
  1323.                     SetClip(newClip = NewRgn());
  1324.  
  1325.                     overflow = inlen + outlen - 31998;
  1326.                     if (overflow > 0) {
  1327.                         if (overflow > inlen) overflow = inlen;
  1328.                         TESetSelect(0, overflow, teIn);
  1329.                         TEDelete(teIn);
  1330.                         inlen -= overflow;
  1331.                     }
  1332.  
  1333.                     inlen = (*teIn)->teLength;
  1334.                     TESetSelect(inlen, inlen, teIn);
  1335.                     if ((inlen) && (outlen < 31998)) {
  1336.                         i = ((*intxt)[inlen - 1] == 13) ? 1 : 2;
  1337.                         for (;i--;) {
  1338.                             TEKey(13, teIn);
  1339.                             ++inlen;
  1340.                         }
  1341.                         styl.tsSize = 4;
  1342.                         TESetSelect(inlen - 1, inlen, teIn);
  1343.                         TESetStyle((doFont | doSize), &styl, false, teIn);
  1344.                         TESetSelect(inlen, inlen, teIn);
  1345.                     }
  1346.  
  1347.                     HLock(outtxt);
  1348.                     TEInsert(*outtxt, outlen, teIn);
  1349.                     DisposeHandle(outtxt);
  1350.  
  1351.                     TESetSelect(inlen, (*teIn)->teLength, teIn);
  1352.  
  1353.                     styl.tsFace = italic;
  1354.                     styl.tsSize = 9;
  1355.                     TESetStyle((doFont | doFace | doSize), &styl, false, teIn);
  1356.  
  1357.                     TECalText(teIn);
  1358.                     pt = TEGetPoint(inlen, teIn);
  1359.                     pt.v -= 12;
  1360.                     TEScroll(0, (*teIn)->viewRect.top - pt.v, teIn);
  1361.  
  1362.                     SetClip(oldClip);
  1363.                     DisposeRgn(oldClip);
  1364.                     DisposeRgn(newClip);
  1365.  
  1366.                     CTEUpdate(teIn, CTEViewFromTE(teIn), false);
  1367.                     CTEAdjustTEBottom(teIn);
  1368.                     CTEAdjustScrollValues(teIn);
  1369.  
  1370.                     break;
  1371.  
  1372.                 case kSoundMssg:
  1373.                     SndPlay(nil, (*frHndl)->doc.sound, false);
  1374.                     break;
  1375.             }
  1376.         }
  1377.  
  1378.         AEDisposeDesc(&theAevt);
  1379.         AEDisposeDesc(&reply);
  1380.             /* Dispose of the descriptors, created or not.
  1381.             ** If not created, no harm done by calling. */
  1382.     }
  1383.  
  1384.     SetPort(oldPort);
  1385.     return(err);
  1386. }
  1387.  
  1388.  
  1389.  
  1390. /*****************************************************************************/
  1391.  
  1392.  
  1393.  
  1394. #pragma segment AppleEvents
  1395. pascal OSErr    ReceiveMssg(AppleEvent *message, AppleEvent *reply, long refcon)
  1396. {
  1397. #ifndef __MWERKS__
  1398. #pragma unused (refcon)
  1399. #endif
  1400.  
  1401.     OSErr            err;
  1402.     long            gameID[2], time[2];
  1403.     short            messageType, i, inlen, outlen, overflow;
  1404.     WindowPtr        oldPort, window;
  1405.     FileRecHndl        frHndl;
  1406.     DescType        actualType;
  1407.     long            actualSize, mssgSize;
  1408.     unsigned long    key;
  1409.     char            hstate;
  1410.     Handle            mssgData, intxt, outtxt;
  1411.     AEAddressDesc    locOfOpponent;
  1412.     RgnHandle        oldClip, newClip;
  1413.     TEHandle        teIn;
  1414.     TextStyle        styl;
  1415.     Point            pt;
  1416.  
  1417.     err = noErr;
  1418.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  1419.         reply,                    /* The AppleEvent.              */
  1420.         keyReplyErr,            /* AEKeyword                 */
  1421.         typeShortInteger,        /* Desired type.             */
  1422.         (Ptr)&err,                /* Pointer to area for data. */ 
  1423.         sizeof(short)            /* Size of data area.         */
  1424.     );
  1425.  
  1426.     err = AEGetParamPtr(        /* GET THE MESSAGE TYPE.     */
  1427.         message,                /* The AppleEvent.              */
  1428.         keyDirectObject,        /* AEKeyword                 */
  1429.         typeShortInteger,        /* Desired type.             */
  1430.         &actualType,            /* Type code.                 */
  1431.         (Ptr)&messageType,        /* Pointer to area for data. */ 
  1432.         2 * sizeof(long),        /* Size of data area.         */
  1433.         &actualSize                /* Returned size of data.     */
  1434.     );
  1435.  
  1436.     if (!err) {
  1437.         err = AEGetParamPtr(        /* GET WINDOW MESSAGE IS FOR. */
  1438.             message,                /* The AppleEvent.               */
  1439.             keyGameID,                /* AEKeyword                  */
  1440.             typeDoubleLong,            /* Desired type.              */
  1441.             &actualType,            /* Type code.                  */
  1442.             (Ptr)&gameID[0],        /* Pointer to area for data.  */ 
  1443.             2 * sizeof(long),        /* Size of data area.          */
  1444.             &actualSize                /* Returned size of data.      */
  1445.         );
  1446.     }
  1447.  
  1448.     if (!err) {            /* See if the requested window exists... */
  1449.         window = GetGameWindow(gameID[1], gameID[0]);
  1450.         if (window) {
  1451.             frHndl = (FileRecHndl)GetWRefCon(window);
  1452.                 /* The game still exists... */
  1453.         }
  1454.         else
  1455.             err = userCanceledErr;
  1456.                 /* User (or computer) canceled game by disconnecting improperly. */
  1457.     }
  1458.  
  1459.     if (!err) {        /* If everything is cool, then do the specific task... */
  1460.  
  1461.         switch(messageType) {
  1462.  
  1463.             case kAmWhiteMssg:
  1464.             case kAmBlackMssg:
  1465.                 messageType ^= 1;
  1466.                 (*frHndl)->doc.configColor       = messageType;
  1467.                 (*frHndl)->doc.configColorChange = true;
  1468.                 (*frHndl)->doc.resync            = kHandResync;
  1469.                 if ((*frHndl)->doc.creator)
  1470.                     SendMssg(frHndl, messageType);
  1471.                         /* If we are the creator, echo the message to make sure
  1472.                         ** that both players aren't the same color. */
  1473.                 break;
  1474.  
  1475.             case kDisconnectMssg:
  1476.                 locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1477.                 AEDisposeDesc(&locOfOpponent);
  1478.                 (*frHndl)->doc.twoPlayer = kLimbo;
  1479.                     /* We set the state of the game to NOT two-player, and NOT
  1480.                     ** what we are now.  This allows us to call SetOpponentType
  1481.                     ** to do all the work we need done.  If we didn't fudge the
  1482.                     ** state of the game (from two-player) then SetOpponentType
  1483.                     ** would send a disconnect message (and we would end up
  1484.                     ** back here.)  This would be an ugly situation, which is
  1485.                     ** completely prevented by fudging the state of the game. */
  1486.                 SetOpponentType(frHndl, kOnePlayer);
  1487.                 break;
  1488.  
  1489.             case kTimeMssg:
  1490.                 AEGetParamPtr(
  1491.                     message,                /* The AppleEvent.              */
  1492.                     keyTime,                /* AEKeyword                 */
  1493.                     typeDoubleLong,            /* Desired type.             */
  1494.                     &actualType,            /* Type code.                 */
  1495.                     (Ptr)&time[0],            /* Pointer to area for data. */ 
  1496.                     2 * sizeof(long),        /* Size of data area.         */
  1497.                     &mssgSize                /* Returned size of data.     */
  1498.                 );
  1499.                 for (i = 0; i < 2; ++i)
  1500.                     (*frHndl)->doc.configTime[i] = time[i];
  1501.                 if ((*frHndl)->doc.resync)
  1502.                     (*frHndl)->doc.configTimeChange = true;
  1503.                 else {
  1504.                     for (i = 0; i < 2; ++i)
  1505.                         (*frHndl)->doc.timeLeft[i] =
  1506.                             (*frHndl)->doc.displayTime[i] = time[i];
  1507.                     UpdateTime(frHndl, false);
  1508.                     DrawTime(frHndl);
  1509.                 }
  1510.                 if ((*frHndl)->doc.creator)
  1511.                     SendMssg(frHndl, kTimeMssg);
  1512.                         /* If we are the creator, echo the message to make sure
  1513.                         ** the clocks are in sync. */
  1514.                 break;
  1515.  
  1516.             case kTextMssg:
  1517.             case kSoundMssg:
  1518.                 /* Both the text and sound message simply send a block of
  1519.                 ** data less than 32k.  Get the data from the AppleEvent
  1520.                 ** for both cases, and then decide what kind of data it is. */
  1521.  
  1522.                 key = (messageType == kTextMssg) ? keyTextMessage : keySoundMessage;
  1523.                 if (!err) {        /* Determine the size of the data... */
  1524.                     err = AEGetParamPtr(
  1525.                         message,                /* The AppleEvent.              */
  1526.                         key,                    /* AEKeyword                 */
  1527.                         typeMssg,                /* Desired type.             */
  1528.                         &actualType,            /* Type code.                 */
  1529.                         nil,                    /* Pointer to area for data. */ 
  1530.                         0,                        /* Size of data area.         */
  1531.                         &mssgSize                /* Returned size of data.     */
  1532.                     );
  1533.                 }
  1534.                 mssgData = nil;
  1535.                 if (!err) {        /* Get the data... */
  1536.                     mssgData = NewHandle(mssgSize);
  1537.                     if (mssgData) {
  1538.                         hstate = LockHandleHigh(mssgData);
  1539.                         err = AEGetParamPtr(
  1540.                             message,                /* The AppleEvent.              */
  1541.                             key,                    /* AEKeyword                 */
  1542.                             typeMssg,                /* Desired type.             */
  1543.                             &actualType,            /* Type code.                 */
  1544.                             *mssgData,                /* Pointer to area for data. */ 
  1545.                             mssgSize,                /* Size of data area.         */
  1546.                             &actualSize                /* Returned size of data.     */
  1547.                         );
  1548.                     }
  1549.                     else err = memFullErr;
  1550.                 }
  1551.                 if (!err) {
  1552.                     if (messageType == kTextMssg) {
  1553.  
  1554.                         styl.tsFont = applFont;
  1555.  
  1556.                         teIn   = (*frHndl)->doc.message[kMessageIn];
  1557.                         intxt  = (*teIn)->hText;
  1558.                         outtxt = mssgData;
  1559.                         inlen  = (*teIn)->teLength;
  1560.                         outlen = GetHandleSize(outtxt);
  1561.  
  1562.                         oldPort = SetFilePort(frHndl);
  1563.                         GetClip(oldClip = NewRgn());
  1564.                         SetClip(newClip = NewRgn());
  1565.  
  1566.                         overflow = inlen + outlen - 31998;
  1567.                         if (overflow > 0) {
  1568.                             if (overflow > inlen) overflow = inlen;
  1569.                             TESetSelect(0, overflow, teIn);
  1570.                             TEDelete(teIn);
  1571.                             inlen -= overflow;
  1572.                         }
  1573.  
  1574.                         inlen = (*teIn)->teLength;
  1575.                         TESetSelect(inlen, inlen, teIn);
  1576.                         if ((inlen) && (outlen < 31998)) {
  1577.                             i = ((*intxt)[inlen - 1] == 13) ? 1 : 2;
  1578.                             for (;i--;) {
  1579.                                 TEKey(13, teIn);
  1580.                                 ++inlen;
  1581.                             }
  1582.                             styl.tsSize = 4;
  1583.                             TESetSelect(inlen - 1, inlen, teIn);
  1584.                             TESetStyle((doFont | doSize), &styl, false, teIn);
  1585.                             TESetSelect(inlen, inlen, teIn);
  1586.                         }
  1587.  
  1588.                         HLock(outtxt);
  1589.                         TEInsert(*outtxt, outlen, teIn);
  1590.  
  1591.                         TESetSelect(inlen, (*teIn)->teLength, teIn);
  1592.  
  1593.                         styl.tsFace = normal;
  1594.                         styl.tsSize = 9;
  1595.                         TESetStyle((doFont | doFace | doSize), &styl, false, teIn);
  1596.  
  1597.                         TECalText(teIn);
  1598.                         pt = TEGetPoint(inlen, teIn);
  1599.                         pt.v -= 12;
  1600.                         TEScroll(0, (*teIn)->viewRect.top - pt.v, teIn);
  1601.  
  1602.                         SetClip(oldClip);
  1603.                         DisposeRgn(oldClip);
  1604.                         DisposeRgn(newClip);
  1605.                         SetPort(oldPort);
  1606.  
  1607.                         CTEUpdate(teIn, CTEViewFromTE(teIn), false);
  1608.                         CTEAdjustTEBottom(teIn);
  1609.                         CTEAdjustScrollValues(teIn);
  1610.  
  1611.                         if ((*frHndl)->doc.doSpeech)
  1612.                             SayText(teIn, nil, (*frHndl)->doc.theVoice);
  1613.  
  1614.                         if (GetControlValue((*frHndl)->doc.beepOnMssg))
  1615.                             if (mssgSize) SysBeep(1);
  1616.                     }
  1617.                     else SndPlay(nil, mssgData, false);
  1618.                 }
  1619.                 if (mssgData) DisposeHandle(mssgData);
  1620.                 if (!err) NotifyUser();
  1621.                 break;
  1622.  
  1623.             case kBeepMssg:
  1624.                 SysBeep(1);
  1625.                 break;
  1626.  
  1627.         }
  1628.     }
  1629.  
  1630.     return(err);
  1631. }
  1632.  
  1633.  
  1634.  
  1635. /*****************************************************************************/
  1636. /*****************************************************************************/
  1637.  
  1638.  
  1639.  
  1640. /* GetGameWindow
  1641. **
  1642. ** Find the window with the specified game ID's. */
  1643.  
  1644. #pragma segment AppleEvents
  1645. WindowPtr    GetGameWindow(long gameID_0, long gameID_1)
  1646. {
  1647.     WindowPeek    window;
  1648.     FileRecHndl    frHndl;
  1649.  
  1650.     for (window = LMGetWindowList(); window; window = window->nextWindow) {
  1651.         if (IsAppWindow((WindowPtr)window)) {
  1652.             frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
  1653.             if (
  1654.                 ((*frHndl)->doc.gameID_0 == gameID_0) &&
  1655.                 ((*frHndl)->doc.gameID_1 == gameID_1)
  1656.             ) return((WindowPtr)window);
  1657.         }
  1658.     }
  1659.  
  1660.     return(nil);
  1661. }
  1662.  
  1663.  
  1664.  
  1665. /*****************************************************************************/
  1666.  
  1667.  
  1668.  
  1669. /* KibitzPortFilter
  1670. **
  1671. ** Don't allow PPCBrowser to show any applications other than Kibitz. */
  1672.  
  1673. #pragma segment AppleEvents
  1674. pascal Boolean    KibitzPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1675. {
  1676. #ifndef __MWERKS__
  1677. #pragma unused (locationName)
  1678. #endif
  1679.  
  1680.     long    type;
  1681.  
  1682.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1683.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1684.             /* The BlockMove is so that we don't get an address error
  1685.             ** on a 68000-based machine due to referencing a long at
  1686.             ** an odd-address. */
  1687.         if (type == gameCreator) return(true);
  1688.     }
  1689.  
  1690.     return(false);
  1691. }
  1692.  
  1693.  
  1694.  
  1695. /*****************************************************************************/
  1696.  
  1697.  
  1698.  
  1699. /* SetOpponentType
  1700. **
  1701. ** Change the opponent type from whatever it currently is to the specified
  1702. ** type.  In so doing, change the state of any controls, etc., that need
  1703. ** to be changed due to the new opponent type. */
  1704.  
  1705. #pragma segment AppleEvents
  1706. void    SetOpponentType(FileRecHndl frHndl, short newOpponentType)
  1707. {
  1708.     WindowPtr        oldPort, window;
  1709.     short            oldOpponentType, hilite, i, toggle;
  1710.     AEAddressDesc    locOfOpponent;
  1711.     Rect            boardRect;
  1712.     ControlHandle    ctl;
  1713.     RgnHandle        oldClip, newClip;
  1714.  
  1715.     if (!(*frHndl)->fileState.window) return;
  1716.  
  1717.     if (!(oldOpponentType = (*frHndl)->doc.arrangeBoard))
  1718.         oldOpponentType = (*frHndl)->doc.twoPlayer;
  1719.  
  1720.     if (oldOpponentType == newOpponentType) return;
  1721.  
  1722.     (*frHndl)->doc.arrangeBoard = false;
  1723.  
  1724.     oldPort = SetFilePort(frHndl);
  1725.     GetPort(&window);
  1726.  
  1727.     oldClip = NewRgn();
  1728.     newClip = NewRgn();
  1729.     GetClip(oldClip);
  1730.  
  1731.     toggle = false;
  1732.     if ((newOpponentType == kArrangeBoard) || (oldOpponentType == kArrangeBoard)) {
  1733.         toggle = true;
  1734.         SetClip(newClip);        /* Prevent stuff from drawing. */
  1735.     }
  1736.  
  1737.     if (oldOpponentType == kTwoPlayer) {
  1738.         SendMssg(frHndl, kDisconnectMssg);
  1739.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1740.         AEDisposeDesc(&locOfOpponent);
  1741.     }
  1742.  
  1743.     if (newOpponentType == kTwoPlayer) {
  1744.         hilite = 0;
  1745.         (*frHndl)->doc.timerRefTick = TickCount();
  1746.         (*frHndl)->doc.creator = true;
  1747.         if ((*frHndl)->doc.myColor == WHITE) (*frHndl)->doc.compMovesBlack = false;
  1748.         else                                 (*frHndl)->doc.compMovesWhite = false;
  1749.     }
  1750.     else {
  1751.         hilite = 255;
  1752.         (*frHndl)->doc.creator = false;
  1753.         (*frHndl)->doc.resync  = kIsMove;
  1754.         (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  1755.     }
  1756.  
  1757.     SetPort(window);
  1758.  
  1759.     if (newOpponentType == kArrangeBoard) {
  1760.         CTEActivate(false, CTEFindActive(window));
  1761.         (*frHndl)->doc.king[BLACK].rookMoves[QSIDE] = 0;
  1762.         (*frHndl)->doc.king[BLACK].rookMoves[KSIDE] = 0;
  1763.         (*frHndl)->doc.king[WHITE].rookMoves[QSIDE] = 0;
  1764.         (*frHndl)->doc.king[WHITE].rookMoves[KSIDE] = 0;
  1765.         (*frHndl)->doc.enPasMove        = 0;
  1766.         (*frHndl)->doc.enPasPawnLoc     = 0;
  1767.         (*frHndl)->doc.arngEnPasMove    = 0;
  1768.         (*frHndl)->doc.arngEnPasPawnLoc = 0;
  1769.         (*frHndl)->doc.numLegalMoves    = 0;
  1770.         (*frHndl)->doc.gameIndex        = 0;
  1771.         (*frHndl)->doc.numGameMoves     = 0;
  1772.         (*frHndl)->doc.compMovesWhite   = false;
  1773.         (*frHndl)->doc.compMovesBlack   = false;
  1774.         AdjustGameSlider(frHndl);
  1775.     }
  1776.     if (oldOpponentType == kArrangeBoard) CTEWindActivate(window, true);
  1777.  
  1778.     if (newOpponentType == kArrangeBoard) {
  1779.         (*frHndl)->doc.arrangeBoard = kArrangeBoard;
  1780.         newOpponentType = kOnePlayer;
  1781.     }
  1782.     (*frHndl)->doc.twoPlayer = newOpponentType;
  1783.  
  1784.     HiliteControl(ctl = (*frHndl)->doc.sendMessage, hilite);
  1785.     OutlineControl(ctl);
  1786.     HiliteControl((*frHndl)->doc.beepOnMove, hilite);
  1787.     HiliteControl((*frHndl)->doc.beepOnMssg, hilite);
  1788.  
  1789.     if (!SoundInputAvaliable()) hilite = 255;
  1790.     HiliteControl((*frHndl)->doc.record, hilite);
  1791.     if (!(*frHndl)->doc.sound) hilite = 255;
  1792.     HiliteControl((*frHndl)->doc.sendSnd, hilite);
  1793.     DrawButtonTitle(frHndl, newOpponentType);
  1794.  
  1795.     if (toggle) {
  1796.         SetClip(oldClip);
  1797.         for (i = 0; i < 2; ++i) (*frHndl)->doc.timeLeft[i] = -1;
  1798.         boardRect = BoardRect();
  1799.         boardRect.left = boardRect.right + 1;
  1800.         boardRect.right = 1000;
  1801.         EraseRect(&boardRect);
  1802.         ImageDocument(frHndl, false);
  1803.     }
  1804.  
  1805.     DisposeRgn(oldClip);
  1806.     DisposeRgn(newClip);
  1807.     SetPort(oldPort);
  1808. }
  1809.  
  1810.  
  1811.  
  1812. /*****************************************************************************/
  1813.  
  1814.  
  1815.  
  1816. #pragma segment AppleEvents
  1817. void    GetFullPathAndAppName(StringPtr path, StringPtr app)
  1818. {
  1819.     ProcessSerialNumber    psn;
  1820.     ProcessInfoRec        pinfo;
  1821.     FSSpec                fss;
  1822.  
  1823.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  1824.     pinfo.processName       = app;
  1825.     pinfo.processAppSpec    = &fss;
  1826.  
  1827.     psn.lowLongOfPSN  = kCurrentProcess;
  1828.     psn.highLongOfPSN = kNoProcess;
  1829.     GetProcessInformation(&psn, &pinfo);
  1830.  
  1831.     PathNameFromDirID(pinfo.processAppSpec->parID, pinfo.processAppSpec->vRefNum, path);
  1832. }
  1833.  
  1834.  
  1835.  
  1836. /*****************************************************************************/
  1837.  
  1838.  
  1839.  
  1840. /* Don't allow DoIPCListPorts to find anything but the finder. */
  1841.  
  1842. #pragma segment AppleEvents
  1843. pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1844. {
  1845. #ifndef __MWERKS__
  1846. #pragma unused (locationName)
  1847. #endif
  1848.  
  1849.     OSType    type;
  1850.  
  1851.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1852.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1853.             /* The BlockMove is so that we don't get an address error
  1854.             ** on a 68000-based machine due to referencing a long at
  1855.             ** an odd-address. */
  1856.         if (type == 'MACS') return(true);
  1857.     }
  1858.  
  1859.     return(false);
  1860. }
  1861.  
  1862. /***/
  1863.  
  1864. /* Don't allow DoIPCListPorts to find anything but Kibitz. */
  1865.  
  1866. #pragma segment AppleEvents
  1867. static pascal Boolean    KibitzFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1868. {
  1869. #ifndef __MWERKS__
  1870. #pragma unused (locationName)
  1871. #endif
  1872.  
  1873.     OSType    type;
  1874.  
  1875.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1876.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1877.             /* The BlockMove is so that we don't get an address error
  1878.             ** on a 68000-based machine due to referencing a long at
  1879.             ** an odd-address. */
  1880.         if (type == 'KBTZ') return(true);
  1881.     }
  1882.  
  1883.     return(false);
  1884. }
  1885.  
  1886. /***/
  1887.  
  1888. OSErr    GetRemoteProcessTarget(FileRecHndl frHndl, AEDesc *retDesc, GRPTProcPtr proc)
  1889. {
  1890.     OSErr            err;
  1891.     char            hstate;
  1892.     PortInfoRec        info;        /* Just one, please. */
  1893.     LocationNameRec    loc;
  1894.     short            indx, reqCount, actCount;
  1895.     TargetID        theID;
  1896.  
  1897.     retDesc->dataHandle = nil;        /* So caller can dispose always. */
  1898.  
  1899.     hstate = LockHandleHigh((Handle)frHndl);
  1900.     loc.locationKindSelector = ppcNBPLocation;        /* Using an NBP construct. */
  1901.     pcpy(loc.u.nbpEntity.objStr,  (*frHndl)->doc.reconnectMachine);
  1902.     pcpy(loc.u.nbpEntity.zoneStr, (*frHndl)->doc.reconnectZone);
  1903.     pcpy(loc.u.nbpEntity.typeStr, "\pPPCToolBox");
  1904.     HSetState((Handle)frHndl, hstate);
  1905.  
  1906.     indx     = 0;
  1907.     reqCount = 1;
  1908.     actCount = 0;
  1909.     err = DoIPCListPorts(&indx, &reqCount, &actCount, &loc, &info, proc);
  1910.     if (err) return(err);
  1911.  
  1912.     if (actCount) {
  1913.         theID.name = info.name;
  1914.         theID.location = loc;
  1915.         err = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), retDesc);
  1916.     }
  1917.  
  1918.     return(err);
  1919. }
  1920.  
  1921.  
  1922.  
  1923.